﻿/*{
author=pk2.2（风铃等）
version=2.0
date=2023/10/12
}*/

/***
AI特别缺粮的时候有限考虑通过买卖粮草来平衡局面
***/

// ## 2023/05/03 # 铃 # 修复bug,美化显示。 ##
// ## 2023/05/02 # 铃 # 适配新的内政系统。 ##
// ## 2023/05/01 # 铃 # 完善了新的参数。 ##
// ## 2022/12/03 # 铃 # 新做了AI的买卖粮草功能。 ##

namespace AI买卖粮草
{

	// ================ CUSTOMIZE ================
	const bool 调试模式 = false;
	// ===========================================

	class Main
	{

		Main()
		{
			pk::bind(202, pk::trigger202_t(onAIRunningOrder));
		}

		void onAIRunningOrder(pk::ai_context @context, pk::building @building, int cmd)
		{
			if (cmd == 据点AI_买卖粮草)
			{
				int force_id;
				int pop_gain_final;
				pk::force@ force = context.force;
				int buildingid = building.get_id();
				int city_id = pk::get_city_id(building.pos);
				pk::city @city = pk::get_city(city_id);
				// city.rate = 70;
				int rate = city.rate / 10;
				int building_id = building.get_id();
				bool is_city = building_id < 城市_末;
				int 城市资金 = pk::get_gold(building);
				int 城市粮草 = pk::get_food(building);
				int 空地数量 = 0;

				int 季度粮收入 = 0;
				if (is_city)
					季度粮收入 = CITY_HARVEST::get_infact_harvest(pk::get_city(building_id));
				else
					季度粮收入 = ch::get_base_p(building_id).base_harvest;

				int 季度粮支出 = pk::get_troops(building) * 25 / 1000 * 9;

				int 季度粮盈余 = 季度粮收入 - 季度粮支出;

				int 预计下季度粮草 = 城市粮草 - turn_to_next_quarter() * 季度粮支出 / 8 + 季度粮收入;

				bool 粮草紧张 = 城市粮草 < 季度粮支出 * 2;

				int 前线状态 = ai::base_statue[building.get_id()];
				int 粮草级别 = 8 - 前线状态;
				粮草级别 = pk::max(粮草级别, 3);

				bool 前线城市 = 前线状态 <= 3;

				string building_name = pk::decode(pk::get_name(building));

				int gold_cost = 0;
				int foods_add_final = 0;
				float 买入系数 = 1.2 + (rate - 5) * 0.2;

				int 金粮差 = 城市资金 - 城市粮草 * 8;
				bool 战争状态 = pk::enemies_around(building);
				int 最大可买粮_资金限制 = 0;
				int person_count = pk::get_person_list(building, pk::mibun_flags(身份_君主, 身份_都督, 身份_太守, 身份_一般)).count;

				if (is_city)
				{
					pk::city @city2 = pk::building_to_city(building);
					空地数量 = city2.max_devs - city2.num_devs;
				}

				int 合意资金下限 = 2500 + 空地数量 * 500 - (战争状态 ? 2000 : 0);
				int 合意资金 = 5000 + 空地数量 * 500;

				if (!is_city)
				{
					合意资金下限 = 1000;
					合意资金 = 3000;
				}

				// 简化算法:70%出兵量带200天,30%够吃2年,总量打底1个季度.且能撑过本季度,最后算下来是1.85倍左右,简化为2倍
				int 合意粮草下限 = pk::max((前线城市 ? 80000 : 30000), pk::get_troops(building) * int(粮草级别 * 0.5));
				int 合意粮草 = pk::max((前线城市 ? 120000 : 50000), pk::get_troops(building) * int(粮草级别 * 0.8));

				// if (buildingid == 铃据点_麦城)
				// 	pk::trace(pk::format("判断:{},rate:{},城市粮草:{},合意粮草{},person_count:{},城市资金:{},合意资金:{}", building_name, rate, 城市粮草, 合意粮草, person_count, 城市资金, 合意资金));

				// 择时买入,如果有好的价格就买粮,如果没有好的价格就不买
				// 价格特别好的时候可以买入1.5倍的量
				// 最多可以买到5倍合意粮草
				if (person_count > 0 and rate >= 4 and 城市资金 > 合意资金)
				{
					// 如果价格特别好的话,可以直接买到合意资金的下限.
					if (rate >= 7)
						最大可买粮_资金限制 = pk::max(0, (城市资金 - 合意资金下限) * rate);
					else
						最大可买粮_资金限制 = pk::max(0, (城市资金 - 合意资金) * rate);

					foods_add_final = pk::min(最大可买粮_资金限制, int((合意粮草 * 5 - 城市粮草) * 买入系数 * ((rate >= 7) ? 1.5 : 1)));
					foods_add_final = pk::min(foods_add_final, pk::get_max_food(building) - pk::get_food(building));
					foods_add_final = pk::min(foods_add_final, 50000 + pk::rand(5000));

					// 可卖的粮太少也没必要
					if (foods_add_final < 10000)
						return;

					gold_cost = foods_add_final / rate;
					pk::add_food(building, foods_add_final, true);
					pk::add_gold(building, -gold_cost, true);
					if (rate >= 7 and foods_add_final > 20000)
						pk::history_log(building.pos, force.color, pk::encode(pk::format("\x1b[1x{}\x1b[0x趁粮价低迷,向商人买入一批粮草。", building_name)));
					if (调试模式)
						pk::trace(pk::format("买粮building_nam:{},城市粮草:{},合意粮草{},合意粮草下限:{},最大可买粮_资金限制:{},买入系数{}, rate:{},foods_add_final :{}", building_name, 城市粮草, 合意粮草, 合意粮草下限, 最大可买粮_资金限制, 买入系数, rate, foods_add_final));
					return;
				}

				//*******************************************买入**********************************************************************************************
				// 紧急买入,只要粮草紧缺就买入粮草,量价好的时候多买,粮价不好的时候正常买
				// 情况紧急的时候,粮草低于合意粮草下限.
				if (person_count > 0 and 城市粮草 < 合意粮草下限 and pk::get_elapsed_months() > 6)
				{
					最大可买粮_资金限制 = pk::max(0, (城市资金 - 合意资金下限) * rate);
					int 最大可买粮_价格修正 = 0;

					if (rate == 3)
						最大可买粮_价格修正 = int((合意粮草下限 - 城市粮草) * 0.8);

					if (rate == 6)
						最大可买粮_价格修正 = pk::max((合意粮草 - 城市粮草) * 2 / 3, 合意粮草下限 - 城市粮草);
					else if (rate == 7)
						最大可买粮_价格修正 = 合意粮草 * 3 - 城市粮草;
					else
						最大可买粮_价格修正 = 合意粮草下限 - 城市粮草;

					foods_add_final = pk::min(最大可买粮_资金限制, 最大可买粮_价格修正);

					// 可卖的粮太少也没必要
					if (foods_add_final < 5000)
						return;

					gold_cost = foods_add_final / rate;
					pk::add_food(building, foods_add_final, true);
					pk::add_gold(building, -gold_cost, true);
					if (foods_add_final > 20000)
						pk::history_log(building.pos, force.color, pk::encode(pk::format("\x1b[1x{}\x1b[0x向商人买入一批粮草。", building_name)));
					if (调试模式)
						pk::trace(pk::format("买粮building_nam:{},城市粮草:{},合意粮草{},合意粮草下限:{},合意资金下限:{},最大可买粮_价格修正:{},最大可买粮_资金限制:{}", building_name, 城市粮草, 合意粮草, 合意粮草下限, 合意资金下限, 最大可买粮_价格修正, 最大可买粮_资金限制));
					return;
				}

				// 卖粮的下限粮草要考虑到出兵量.70%出兵量带200天,30%够吃2年,总量打底1个季度.且能撑过本季度

				int 粮草卖出量 = 0;

				粮草卖出量 = 预计下季度粮草 - 合意粮草;

				// 择时卖出,如果有好的价格就卖粮,如果没有好的价格就不卖
				// 价格特别好的时候可以,卖出入1.5倍的量
				if (person_count > 0 and rate <= 4 and 季度粮盈余 > 0 and pk::get_elapsed_months() > 6 and !战争状态)
				{

					// 粮价为4的时候只卖一半
					foods_add_final = int(粮草卖出量 * ((rate == 4) ? 0.5 : 1.0));
					foods_add_final = pk::min(foods_add_final, (pk::get_max_gold(building) - pk::get_gold(building)) * rate);
					foods_add_final = pk::min(foods_add_final, 50000 + pk::rand(5000));

					// 可卖的粮太少也没必要
					if (foods_add_final < 10000)
						return;

					gold_cost = foods_add_final / rate;
					pk::add_food(building, -foods_add_final, true);
					pk::add_gold(building, gold_cost, true);
					if (rate <= 3 and foods_add_final > 20000)
						pk::history_log(building.pos, force.color, pk::encode(pk::format("\x1b[1x{}\x1b[0x趁粮价高企,向商人卖出一批粮草。", building_name)));
					return;
				}
			}
		}

		int turn_to_next_quarter()
		{

			int n = (2 - (pk::get_month() - 1) % 3) * 3 + (pk::get_day() == 21 ? 0 : (pk::get_day() == 11 ? 1 : 2));
			return n + 1;
		}

		// int func153(pk::building@ building)
		// {
		//   int result = prev_callback_153(building);
		//   return result;
		// }

	} // class

	Main main;
}